﻿#include "stdafx.h"
#if _QG_USE_D11
#include "qg/qgasv.h"
#include "qg_d11_dev.h"
#include "qg_trace.h"

//////////////////////////////////////////////////////////////////////////
// 렌더 타겟 특히, 기본 렌더 타겟

D11Render::D11Render()
: _sc(NULL), _rtview(NULL), _dsview(NULL), _dstex(NULL)
{
	k_zero_1(&_vp);
}

//
D11Render::~D11Render()
{
	// 어짜피 Dispose() 강제로 호출하기 때문에 패스
	//Dispose();
}

//
void D11Render::Dispose()
{
	kunk_reset(&_rtview);
	kunk_reset(&_dsview);
	kunk_reset(&_dstex);
	kunk_reset(&_sc);
}

//
HRESULT D11Render::Create(IDXGIFactory* factory, ID3D11Device* device, UINT sacnt, UINT saqlt, kint width, kint height, HWND hwnd, bool windowed)
{
	HRESULT hr;

	// 스왑체인
	DXGI_SWAP_CHAIN_DESC sd;
	sd.BufferDesc.Width = width;
	sd.BufferDesc.Height = height;
	sd.BufferDesc.RefreshRate.Numerator = 0;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.SampleDesc.Count = sacnt;
	sd.SampleDesc.Quality = saqlt;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount = 1;
	sd.OutputWindow = hwnd;
	sd.Windowed = windowed;
	sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	sd.Flags = 0;

	hr = factory->CreateSwapChain(device, &sd, &_sc);
	if (FAILED(hr))
		return hr;

	// 레이아웃에서 나머지 만듦
	return Layout(device, sacnt, saqlt, width, height);
}

//
HRESULT D11Render::Layout(ID3D11Device* device, UINT sacnt, UINT saqlt, kint width, kint height)
{
	HRESULT hr;

	// 먼저 제거
	kunk_reset(&_rtview);
	kunk_reset(&_dsview);
	kunk_reset(&_dstex);

	// 뷰포트
	_vp.TopLeftX = 0.0f;
	_vp.TopLeftY = 0.0f;
	_vp.Width = (float)width;
	_vp.Height = (float)height;
	_vp.MinDepth = 0.0f;
	_vp.MaxDepth = 1.0f;

	// 스왑체인 크기 변경
	if (FAILED(hr = _sc->ResizeBuffers(1, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0)))
		return hr;

	// 렌더 타깃 뷰
	ID3D11Texture2D* backbuffer;
	if (FAILED(hr = _sc->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backbuffer)))
	{
		// 백버퍼 얻기 실패
		return hr;
	}

	hr = device->CreateRenderTargetView(backbuffer, 0, &_rtview);

	backbuffer->Release();

	if (FAILED(hr))
	{
		// 렌더 타겟뷰 만들기 실패
		return hr;
	}

	// 깊이 스텐실 버퍼 및 뷰
	D3D11_TEXTURE2D_DESC dsd;
	dsd.Width = width;
	dsd.Height = height;
	dsd.MipLevels = 1;
	dsd.ArraySize = 1;
	dsd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	dsd.SampleDesc.Count = sacnt;
	dsd.SampleDesc.Quality = saqlt;
	dsd.Usage = D3D11_USAGE_DEFAULT;
	dsd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	dsd.CPUAccessFlags = 0;
	dsd.MiscFlags = 0;

	if (FAILED(hr = device->CreateTexture2D(&dsd, 0, &_dstex)))
		return hr;

	if (FAILED(hr = device->CreateDepthStencilView(_dstex, 0, &_dsview)))
		return hr;

	return S_OK;
}

//
bool D11Render::Flush()
{
	return SUCCEEDED(_sc->Present(0, 0));
}

//
void D11Render::Render(ID3D11DeviceContext* context)
{
	context->OMSetRenderTargets(1, &_rtview, _dsview);
	context->RSSetViewports(1, &_vp);
}

#endif	// _QG_USE_D11
